package br.ufrgs.inf.cwsmart.matcher;

import java.util.List;
import java.util.Map;

import br.ufrgs.inf.cwsmart.CWSMartFramework;
import br.ufrgs.inf.cwsmart.exception.FrameworkException;
import br.ufrgs.inf.cwsmart.util.Logger;


/**
 * Abstract matcher class for a matcher module that checks the
 * acceptability of a new CWS that wants to join the mart
 *   
 * @author Rodrigo S Lumertz
 */
public abstract class Matcher
{	
	
	/**
	 * The constructor automatically called by the class that implements the matcher 
	 */
	public Matcher() {				
	}
		
	/**
	 * It adds a CWS to the CWSMart in case of acceptance or recommends a CWSMart that eventually
	 * can accept the CWS in case of non acceptance in this mart. Additionally can return an Error 
	 * string in case of failure to add and to recommend.
	 * 
	 * @param cwsPath The CWS that is trying to join
	 * @param language The language specification of the cws candidate
	 * 
	 * @return An String that can be:
	 * "OK" in case of success in the joining
	 * "<idCWSMart>" in case of recommendation
	 * "NOK" in case of failure in the joining and failure in the recommendation 
	 * 
	 * @throws FrameworkException
	 */
	public String joinCWSMart(String cwsPath, String language, String... wsdlPaths) 
		throws FrameworkException {
	
		Logger.logger.log(Logger.INFORMATIONAL_LEVEL, "Matcher.joinCWSMart", 
				"New " + language + " CWS candidate: " + cwsPath);
		
		String result = "";		
		
		Logger.logger.log(Logger.DEBUG2_LEVEL, "Matcher.joinCWSMart", "Instantiatiang CWSProperties");
		CWSProperties cwsProperties = instantiateCWSProperties(language);		
		
		if (cwsProperties != null) {
			try {
				Logger.logger.log(Logger.DEBUG2_LEVEL, "Matcher.joinCWSMart", "Parsing the cws description...");
				cwsProperties.parse(cwsPath);
			} catch (Exception ex) {
				Logger.logger.log(Logger.WARNING_LEVEL, "Matcher.joinCWSMart", 
						"Error: " + ex.getMessage());
				throw new FrameworkException(FrameworkException.ErrorCode.UNKNOWN_ERROR);
			}
			
			List<String> cwsFunctionalities = cwsProperties.getFunctionalities();
			Map<String, String> cwsAttributes = cwsProperties.getAttributes();
			
			Logger.logger.log(Logger.DEBUG1_LEVEL, "Matcher.joinCWSMart", "Checking Acceptability...");
			if (checkAcceptability(cwsFunctionalities, cwsAttributes)) {
				//uses description module to add the CWS
				Logger.logger.log(Logger.DEBUG1_LEVEL, "Matcher.joinCWSMart", "CWS Accepted, calling Description module...");
				CWSMartFramework.getInstance().getDescriptionInstance().addCWS(cwsPath, language, wsdlPaths);
				result = "OK"; 
			} else {
				//tries recommendation
				Logger.logger.log(Logger.DEBUG1_LEVEL, "Matcher.joinCWSMart", "CWS refused, calling Recommendation module...");
				result = CWSMartFramework.getInstance().
					getRecommendationInstance().RecommendCWSMart(cwsFunctionalities, cwsAttributes);
			}
			
		} else {	
			Logger.logger.log(Logger.WARNING_LEVEL, "Matcher", 
					"Exception will be raised because no CWSProperties could be found");
			throw new FrameworkException(FrameworkException.ErrorCode.EXTENSIBLE_INSTANCE_NOT_FOUND);
		}
		
		return result;
	}

	/**
	 * Checks if the candidate CWS can join this CWSMart 
	 * 
	 * @param cwsFunctionalities The functionality of the CWS
	 * @param cwsProperties The properties of the CWS
	 * 
	 * @return A boolean that indicates if the join can take place
	 * @throws FrameworkException In case of extensible class 
	 * not implemented, semantic comparison exception or rules checking exception
	 */	
	protected boolean checkAcceptability(List<String> cwsFunctionalities, Map<String, String> cwsAttributes) 
		throws FrameworkException {
		
		boolean isCWSAccepted = false;
		
		if (CWSMartFramework.getInstance().getMartPropertiesInstance() != null) {					
			List<String> martFunctionalities = CWSMartFramework.getInstance().
				getMartPropertiesInstance().getMartFunctionalities();			 
			Map<String, String> martRules = CWSMartFramework.getInstance().
				getMartPropertiesInstance().getMartRules();
						
			if (checkSemantic(cwsFunctionalities, martFunctionalities) && 
					checkRule(cwsAttributes, martRules)) {
				isCWSAccepted = true;
			} else {
				isCWSAccepted = false;
			}
			
		} else {		
			Logger.logger.log(Logger.WARNING_LEVEL, "Matcher", 
				"Exception will be raised because no MartProperties could be found");
			throw new FrameworkException(FrameworkException.ErrorCode.EXTENSIBLE_INSTANCE_NOT_FOUND);
		}				
		
		return isCWSAccepted;
	}
	
	/**
	 * Semantically compares the functionalities of a CWS and a CWSMart
	 *
	 * @param cwsFunctionalities The CWS's functionalities 
	 * @param martFunctionalities The CWSMart's functionalities
	 * 
	 * @return A boolean that indicates whether semantically the CWS
	 * can join the mart
	 */
	public abstract boolean checkSemantic(List<String> cwsFunctionalities, 
			List<String> martFunctionalities) throws FrameworkException;
	
	
	/**
	 * Verify if there is room for accepting this CWS in this CWSMart based
	 * on the rules that regulate the content of this CWSMart
	 * 
	 * @param cwsProperties The properties of this CWS
	 * @param martRules The rules of this mart
	 * 
	 * @return A boolean that indicates whether the CWS can join the mart
	 */
	protected abstract boolean checkRule(Map<String, String> cwsProperties, Map<String, String> martRules)
		throws FrameworkException;
	
	
	/**
	 * Instantiate a class that knows how to proceed with the CWS description
	 * language in order to obtain functionalities and properties of the CWS
	 * 
	 * @param cwsFile The CWS description file
	 * @param language The CWS description file language
	 * 
	 * @return An instance of a class that can operate the CWS description
	 * @throws FrameworkException An exception in case of language not supported
	 */
	protected abstract CWSProperties instantiateCWSProperties(String language) 
		throws FrameworkException;
		
}